package com.jmb.api.core.parser;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.jmb.api.common.constant.ParserConstant;
import com.jmb.api.common.exception.LeaseException;
import com.jmb.api.common.exception.ParseException;
import com.jmb.api.common.exception.SqlException;
import com.jmb.api.common.result.RelyType;
import com.jmb.api.common.result.ResultCodeEnum;
import com.jmb.api.common.utils.*;
import com.jmb.api.core.Env;
import com.jmb.api.core.NodeRequest;
import com.jmb.api.model.entity.ApiTestCacheParameterLog;
import com.jmb.api.model.entity.DbConnection;
import com.jmb.api.model.entity.ExecuteInterfaceCaseParam;
import com.jmb.api.model.to.api.rely.ApiTestCaseRelyDataTO;
import com.jmb.api.model.vo.api.cache.ApiTestCacheParameterVo;
import com.jmb.api.model.vo.api.log.ApiTestCaseExecuteLogVO;
import com.jmb.api.model.vo.api.rely.ApiRelyDataVO;
import com.jmb.api.model.vo.db.DbVO;
import com.jmb.api.model.vo.rely.RelyDataVO;
import com.jmb.api.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Component
public class Parser implements NodeRequest {
    @Autowired
    private ApiCaseSuiteService caseSuiteService;
    @Autowired
    private ApiTestCaseRelyDataService caseRelyDataService;
    @Autowired
    private DbService dbService;
    @Autowired
    private ApiTestCaseExecuteLogService caseExecuteLogService;
    @Autowired
    private RelyDataService relyDataService;
    @Autowired
    private Env env;
    @Autowired
    private ApiTestCacheParameterService cacheParameterService;
    @Autowired
    private ApiTestCaseService caseService;
    @Autowired
    private ApiTestCacheParameterLogService cacheParameterLogService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ApiTestCaseRelyDataService apiTestCaseRelyDataService;
    @Autowired
    private ApiTestCaseService apiTestCaseService;



    /**
     * 解析依赖
     * @param text 待清洗数据
     * @param chainNo 调用链路跟踪，每次调用均会把自增日志编号写入缓存里，在序列化
     * @param suiteId 测试套件编号ID，主要用于调用入口，为测试套件时确定运行环境，否则就传null
     * @param isFailedRetry 判断执行日志是否为失败重试， 0是，1否，主要测试报告断言情况
     * @param suiteLogDetailNo 仅记录重跑和真正运行的, 会包括用例所依赖的case
     * @param globalHeaders 测试套件的全局请求头
     * @param globalParams 测试套件的全局请求参数
     * @param globalData 测试套件的全局数据
     * @param casePreNo 前置用例UUID编号
     * @return 返回解析后的数据
     */
    public String parseDependency(String text, String chainNo, Integer suiteId, Integer isFailedRetry, String suiteLogDetailNo,
                                  HashMap<String,Object> globalHeaders, HashMap<String,Object> globalParams,
                                  HashMap<String,Object> globalData, String casePreNo) throws ParseException, SqlException {
        if (text == null || text.isEmpty()){
            return text;
        }
        // 解析处理器
        text = parseProcessor(text, suiteLogDetailNo, casePreNo, chainNo);
        log.info("--------------------------------------开始字符ParseUtil串解析流程--------------------------------------");
        log.info("--------------------------------------待解析字符串原文={}", text);
        // 设置运行环境
        Integer runEnv;
         if (suiteId ==null){
             // runEnv 赋值4
             runEnv = 4;
         }else{
             runEnv = caseSuiteService.findApiCaseSuiteById(suiteId).getRunDev();
         }
        log.info("--------------------------------------运行环境={}, 0dev 1test 2stg 3prod 4debug", runEnv);
         // 正则匹配
        Pattern compile = Pattern.compile(ParserConstant.DEPENDENCY_REGEX);
        // 匹配到则替换
        Matcher matcher = compile.matcher(text);
        // 循环匹配
        while (matcher.find()){
            //   获取匹配到的字符串
            String findStr = matcher.group();
            // 从匹配到的字符串中提取依赖名称，假设依赖名称被括号包围，去除括号
            String relyName = findStr.substring(2, findStr.length() - 1);
            String relyExpress = relyName; // 带索引的
            log.info("获取到的relyName={}", relyName);
           // 进入数组下标取值模式
            if (Pattern.matches(ParserConstant.DEPENDENCY_REGEX_INDEX, relyName)){
                // 记录运行开始时间
                long start = TimeUtil.now();
                log.info("--------------------------------------进入数组下标取值模式");
                if (relyName.indexOf("[") !=relyName.lastIndexOf("[")
                        || relyName.indexOf("]") != relyName.lastIndexOf("]")){
                    log.error("数组下标取值模式，数组下标格式错误，索引出错");
                    throw new LeaseException(ResultCodeEnum.WEB_API_DEPENDENCY_INDEX_ERROR);
                }
                // 提取数组下标
                String indexStr = relyName.substring(relyName.indexOf("[") + 1, relyName.length() - 1);
                // 提取数组下标值
                int index = Integer.parseInt(indexStr);
                log.info("获取到的数组下标={}", index);
                // 提取数组名称去除下标后
                relyName = relyName.substring(0, relyName.indexOf("["));
                log.info("去除下标后的真实relyName={}", relyName);
                // 获取依赖数据
                ApiRelyDataVO relyDataVO = caseRelyDataService.selectRelyDataByName(relyName);
                if (relyDataVO == null){
                    log.error("数组下标取值模式，依赖数据不存在");
                    throw new LeaseException(ResultCodeEnum.WEB_API_DEPENDENCY_NOT_EXIST);
                }
                // 获取caseID用例编号
                Integer caseId = relyDataVO.getRelyCaseId();
                log.info("获取到的依赖数据caseID={}", caseId);
                // 执行用例执行日志的ID
                Integer executeLogId = caseService.executeCase(
                        new ExecuteInterfaceCaseParam(
                                caseId, "系统调度", null, chainNo, suiteId, isFailedRetry, suiteLogDetailNo, globalHeaders, globalParams
                                , globalData, 4, casePreNo, false));
                log.info("执行用例编号={}，执行日志编号={}", caseId, executeLogId);
                ApiTestCaseExecuteLogVO executeLogVO = caseExecuteLogService.findExecute(executeLogId);
                // 获取响应体
                String responseBody = executeLogVO.getResponseBody();
                // 获取响应头
                String responseHeaders = executeLogVO.getResponseHeaders();
                // 获取数据类型
                Integer contentType = relyDataVO.getContentType();
                // 获取提取表达式
                String extractExpression = relyDataVO.getExtractExpression();
                try {
                    if (contentType == 0){
                        // json格式
                        ArrayList jsonPathArray = JSONObject.parseObject(ParseUtil.parseJson(responseBody, extractExpression), ArrayList.class);
                        if (jsonPathArray.isEmpty()) {
                            String Message = String.format("case 依赖项 [%s] json-path 提取内容为空, " +
                                    "执行 case id 为 [%s], 执行 execution log id 为 [%s], 执行 expression 为 [%s]", relyName, caseId, executeLogId, extractExpression);
                            log.error(Message);
                            throw new ParseException(Message);
                        }
                        try{
                            String value = jsonPathArray.get(index).toString();
                            redisUtil.stackPush(chainNo,chainNode(RelyType.INTERFACE_JSON,executeLogId,relyExpress,
                                    value,TimeUtil.now()- start,extractExpression));
                            text = text.replace(findStr,value);
                            log.info("jsonPath提取值并替换后的结果={}",text);
                        }catch (Exception e){
                            String Message =String.format("json-path 索引超出范围, case 依赖项 [%s], index [%s]", relyName, index);
                            // 打印异常
                            log.error(Message);
                            // 抛出异常
                            throw new ParseException( Message);
                        }

                    }
                    else if (contentType == 1){
                        // html
                        ArrayList xpathArray = JSONObject.parseObject(ParseUtil.parseXml(responseBody, extractExpression),ArrayList.class);
                         if (xpathArray.isEmpty()) {
                            String Message = String.format("case 依赖项 [%s] xpath 提取内容为空, " +
                                    "执行 case id 为 [%s], 执行 execution log id 为 [%s], 执行 expression 为 [%s]", relyName, caseId, executeLogId, extractExpression);
                            log.error(Message);
                            throw new ParseException(Message);
                        }
                         try {
                              String value = xpathArray.get(index).toString();
                               redisUtil.stackPush(chainNo,chainNode(RelyType.INTERFACE_HTML,executeLogId,relyExpress,
                                       value,TimeUtil.now()- start,extractExpression));
                               text = text.replace(findStr,value);
                               log.info( "xpath提取值并替换后的结果={}",text);
                         }catch (Exception e){
                             String Message =String.format("xpath 索引超出范围, case 依赖项 [%s], index [%s]", relyName, index);
                             log.error(Message);
                              throw new ParseException( Message);
                         }
                    } else if (contentType == 2) {
                        // 处理headers
                        JSONArray headerArray =(JSONArray) JSONObject.parseObject(responseHeaders, HashMap.class).get(extractExpression);
                        if (null == headerArray || headerArray.isEmpty()){
                             String Message = String.format("case 依赖项 [%s] headers 提取内容为空, " +
                                    "执行 case id 为 [%s], 执行 execution log id 为 [%s], 执行 expression 为 [%s]", relyName, caseId, executeLogId, extractExpression);
                                    log.error(Message);
                                     throw new ParseException(Message);
                        }
                        try {
                             String value = headerArray.get(index).toString();
                             redisUtil.stackPush(chainNo,chainNode(RelyType.INTERFACE_HEADER,executeLogId,relyExpress,
                                     value,TimeUtil.now()- start,extractExpression));
                             text = text.replace(findStr,value);
                        }catch (Exception e){
                             String Message =String.format("headers 索引超出范围, case 依赖项 [%s], index [%s]", relyName, index);
                              log.error(Message);
                               throw new ParseException( Message);
                        }
                    }else {
                        throw new LeaseException( ResultCodeEnum.NOT_SUPPORT_DATA_TYPE);
                    }

                }catch (LeaseException e){
                    log.error("不支持该数据类型");
                    throw new LeaseException( ResultCodeEnum.NOT_SUPPORT_DATA_TYPE);
                }
                catch (NumberFormatException e){
                    log.error("数组索引参数不合法");
                    throw new ParseException("数组索引参数不合法");
                }
                catch (Exception e){
                    log.error("解析数据异常,数组错误，附加项过多:  {}", ExceptionUtil.msg(e));
                     throw new ParseException( e.getMessage());
                }
            }
            // 进入预置方法/动态SQL模式
            else if (Pattern.matches(ParserConstant.DEPENDENCY_REGEX_PARAMS,relyName)){
                long  start = TimeUtil.now();
                log.info("--------------------------------------进入预置方法/动态SQL模式");
                if (relyName.indexOf("(") != relyName.lastIndexOf("(") ||
                        relyName.indexOf(")") != relyName.lastIndexOf(")")) {
                    String nf = String.format("依赖项初始化方法或SQL [%s] 语法错误", relyName);
                    log.error(nf);
                    throw new ParseException(nf);
                }
                String methodName = relyName.substring(0, relyName.indexOf("("));
                log.info("预置方法名称/动态SQL依赖名称={}", methodName);
                String[] params = relyName.substring(relyName.indexOf("(") + 1, relyName.length() - 1)
                        .replaceAll(",\\s+", ",").split(",");
                RelyDataVO relyDataVO = relyDataService.findRelyDataByName(methodName);
                if (null == relyDataVO) {
                    String nf = String.format("初始化方法或 sql [%s] 请检查url", relyName);
                    log.error(nf);
                    throw new ParseException(nf);
                }
                Integer type = relyDataVO.getType();
                // 进行反射
                if ( type == 1){
                    log.info( "--------------------------------------进入初始化方法模式");
                    Method method;
                    String methodReturnValue;
                    Class<?> clazz;
                    Constructor<?> constructor;
                    try {
                        clazz = Class.forName("com.jmb.api.common.utils.InvokeCenter");
                        constructor = clazz.getConstructor(Integer.class);
                    } catch (ClassNotFoundException | NoSuchMethodException e ) {
                        String nf = "com.jmb.apiplatform.common.InvokeCenter 构造函数未找到";
                        log.error(nf);
                        log.error(ExceptionUtil.msg(e));
                        throw new RuntimeException(e);
                    }
                    if (params.length == 1 && "".equals(params[0])){
                        params = new String[0];
                    }
                    try {
                        // 尝试固定长度参数
                        clazz = Class.forName("com.jmb.api.common.utils.InvokeCenter");
                        constructor = clazz.getConstructor(Integer.class);
                        Class[] paramsList = new Class[params.length];
                        for (int i = 0; i < params.length; i++) {
                            paramsList[i] = String.class;
                            params[i] = params[i].substring(1,params[i].length()-1);
                        }
                        log.info("固定长度参数，方法名称={}，方法参数={}",methodName, Arrays.toString(params));
                        method = clazz.getMethod(methodName, paramsList);
                        methodReturnValue = (String) method.invoke(constructor.newInstance(runEnv), params);
                        log.info("获取到的method{}", methodReturnValue);
                        log.info("固定长度参数，预置方法执行并替换后的结果={}", text);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                        // 尝试可变参数
                        try {
                            log.info("固定长度参数异常，尝试可变长度参数，方法名称={}，方法参数={}", methodName, Arrays.toString(params));
                            method = clazz.getMethod(methodName, String[].class);
                            methodReturnValue = (String) method.invoke(constructor.newInstance(runEnv), (Object) params);
                            log.info("固定长度参数异常，尝试可变长度参数，预置方法执行并替换后的结果={}", text);
                        } catch (Exception ee) {
                            String nf = String.format("依赖初始化方法执行错误，可能找不到或参数错误，方法为 [%s], 参数是[%s]", methodName, Arrays.toString(params));
                            log.error(nf);
                            log.error(ExceptionUtil.msg(ee));
                            throw new ParseException(ExceptionUtil.msg(ee));
                        }
                    }
                    redisUtil.stackPush(chainNo,chainNode(RelyType.INVOKE, relyDataVO.getId(), relyName, methodReturnValue, TimeUtil.now()-start, null));
                    text = text.replace(findStr,methodReturnValue);

                }else if (type >= 2 && type<=6){
                    //sql 2sql-select 3sql-insert 4sql-update 5sql-delete 6sql-script
                    log.info("--------------------------------------进入动态SQL模式");
                    if (params.length == 1 && "".equals(params[0])) {
                        params = null;
                    } else {
                        for (int i = 0; i < params.length; i++) {
                            // 去除首尾引号
                            params[i] = params[i].substring(1, params[i].length() - 1);
                        }
                    }
                    Integer datasourceId = relyDataVO.getDatasourceId();
                    if (null == datasourceId) {
                        String nf = String.format("找不到数据源，数据源id为 [%s]", datasourceId);
                        log.error(nf);
                        throw new ParseException(nf);
                    }
                    DbVO dbVO = dbService.findDbById(datasourceId);
                    int status = dbVO.getStatus();
                    if (status == 1) {
                        String nf = String.format("找不到数据源，数据源id为 [%s]", datasourceId);
                        log.error(nf);
                        throw new ParseException(nf);
                    }
                    DbConnection datasource = env.datasource(dbVO, runEnv);
                    String url = datasource.getUrl();
                    String username = datasource.getUsername();
                    String password = datasource.getPassword();
                    // 支持动态sql
                    String sql = relyDataVO.getValue();
                    if (relyDataVO.getValue() != null) {
                        log.info("开始解析SQL，解析前SQL={}", sql);
                        sql = parseDependency(sql, chainNo, suiteId, isFailedRetry, suiteLogDetailNo, globalHeaders, globalParams, globalData, casePreNo);
                        log.info("解析SQL完成，解析后SQL={}", sql);
                    }
                    log.info("SQL执行参数，SQL={}, params={}", sql, params);

                    String sqlResult;
                    if (type == 2) { // 查询
                        if (relyDataVO.getAnalysisRely() == 0) {
                            sqlResult = JdbcUtil.selectFirst(url, username, password, sql, params);
                        } else {
                            sqlResult = JdbcUtil.selectFirst(url, username, password, relyDataVO.getValue(), params);
                        }
                        redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_SELECT, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                    } else if (type == 3) { // 新增
                        if (relyDataVO.getEnableReturn() == 0) {
                            sqlResult = String.valueOf(JdbcUtil.insert(url, username, password, sql, params));
                        } else {
                            JdbcUtil.insert(url, username, password, sql, params);
                            sqlResult = "";
                        }
                        redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_INSERT, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                    } else if (type == 4) { // 修改
                        if (relyDataVO.getAnalysisRely() == 0) {
                            sqlResult = JdbcUtil.update(url, username, password, sql, params);
                        } else {
                            sqlResult = JdbcUtil.update(url, username, password, relyDataVO.getValue(), params);
                        }
                        redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_UPDATE, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                    } else if (type == 5) { // 删除
                        if (relyDataVO.getAnalysisRely() == 0) {
                            sqlResult = JdbcUtil.delete(url, username, password, sql, params);
                        } else {
                            sqlResult = JdbcUtil.delete(url, username, password, relyDataVO.getValue(), params);
                        }
                        redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_DELETE, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                    } else { // 脚本
                        if (relyDataVO.getAnalysisRely() == 0) {
                            sqlResult = JdbcUtil.script(sql, url, username, password, true);
                        } else {
                            sqlResult = JdbcUtil.script(relyDataVO.getValue(), url, username, password, true);
                        }
                        redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_SCRIPT, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                    }
                    text = text.replace(findStr, sqlResult);

                }
            }
            // 进入普通依赖数据模式
            else {
                long start = TimeUtil.now();
                log.info("-------------------------------------进入普通依赖数据模式");
                ApiTestCaseRelyDataTO caseRelyDataTO = new ApiTestCaseRelyDataTO();
                caseRelyDataTO.setRelyName(relyName);
                ApiRelyDataVO relyData = apiTestCaseRelyDataService.selectRelyDataByName(relyName);
                if (relyData == null) {
                    RelyDataVO relyDataVO = relyDataService.findRelyDataByName(relyName);
                    if (relyDataVO == null){
                        String nf = String.format("找不到依赖数据，依赖数据名称为 [%s]", relyName);
                        log.error(nf);
                        throw new ParseException(nf);
                    }else {
                        Integer type = relyDataVO.getType();
                        log.info("获取到的type是{}",type);
                        if (type==0){
                            String value = relyDataVO.getValue();
                            text = text.replace(findStr, value);
                            redisUtil.stackPush(chainNo,chainNode(RelyType.CONST,type,relyName,value,TimeUtil.now()-start,null));
                        }else  if (type>=2 && type<=6){
                            Integer datasourceId = relyDataVO.getDatasourceId();
                            if (datasourceId == null){
                                String nf = String.format("找不到数据源,数据原id是[%s]", datasourceId);
                                log.error(nf);
                                throw new ParseException(nf);
                            }
                            DbVO dbVO = dbService.findDbById(datasourceId);
                            Integer status = dbVO.getStatus();
                            if (status == 1 ){
                                String nf = String.format("找不到数据源,数据源id是[%s]", datasourceId);
                                log.error(nf);
                                throw new ParseException(nf);
                            }
                            DbConnection datasource = env.datasource(dbVO, runEnv);
                            String url = datasource.getUrl();
                            String username = datasource.getUsername();
                            String password = datasource.getPassword();
                            String sql = relyDataVO.getValue();
                            if (relyDataVO.getValue() !=null){
                                log.info("开始解析Sql，解析前的Sql是={}",sql);
                                parseDependency(sql,chainNo,suiteId,isFailedRetry,suiteLogDetailNo,globalHeaders,globalParams,globalData,casePreNo);
                                log.info("解析SQL完成，解析后的Sql是={}",sql);
                            }
                            log.info("Sql执行参数，Sql={}",sql);
                            String sqlResult;
                            if (type==2){
                                // 查询
                                if (relyDataVO.getAnalysisRely() == 0){
                                    log.info("开始查询Sql={}",sql);
                                    sqlResult = JdbcUtil.selectFirst(url,username,password,sql,null);
                                }else {
                                    sqlResult = JdbcUtil.selectFirst(url,username,password,relyDataVO.getValue(),null);
                                }
                                log.info("未处理的方法");
                                redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_SELECT, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                            }else if (type ==3){
                                // 新增
                                if (relyDataVO.getEnableReturn() == 0){
                                    sqlResult = String.valueOf(JdbcUtil.insert(url,username,password,sql,null));
                                }
                                else {
                                    JdbcUtil.insert(url,username,password,sql,null);
                                    sqlResult = "";
                                }
                                redisUtil.stackPush(chainNo,chainNode(RelyType.SQL_INSERT, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));

                            }else if (type==4){
                                // 修改
                                if (relyDataVO.getAnalysisRely() == 0){
                                    sqlResult = JdbcUtil.update(url,username,password,sql,null);
                                }
                                else {
                                    sqlResult = JdbcUtil.update(url,username,password,relyDataVO.getValue(),null);
                                }
                                redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_UPDATE, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));

                            }else if(type==5){
                                // 删除
                                if (relyDataVO.getAnalysisRely() == 0){
                                    sqlResult = JdbcUtil.delete(url,username,password,sql,null);
                                }
                                else {
                                    sqlResult = JdbcUtil.update(url,username,password,sql,null);
                                }
                                redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_DELETE, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));

                            }else {
                                // 脚本
                               if (relyDataVO.getAnalysisRely() == 0){
                                   sqlResult = JdbcUtil.script(sql,url,username,password,true);
                               }
                               else {
                                   sqlResult = JdbcUtil.script(relyDataVO.getValue(),url,username,password,true);
                               }
                                redisUtil.stackPush(chainNo, chainNode(RelyType.SQL_SCRIPT, relyDataVO.getId(), relyName, sqlResult, TimeUtil.now()-start, null));
                            }
                            text = text.replace(findStr,sqlResult);
                        }
                        else if (type == 6){
                            String format = String.format("依赖项 [%s]未找到，请确保它不是方法", relyName);
                            log.error(format);
                            throw new ParseException(format);
                        }
                    }
                }
                else {
                    Integer caseId = relyData.getRelyCaseId();
                    Integer executeLogId = apiTestCaseService.executeCase(new ExecuteInterfaceCaseParam(caseId, "系统调度", null, chainNo, suiteId,
                            isFailedRetry, suiteLogDetailNo, globalHeaders, globalParams, globalData, 4, casePreNo, false));
                    if (caseExecuteLogService.findExecute(executeLogId).getStatus() !=0){
                        String format = String.format("依赖相关的ID是 [%s] 执行失败&错误，" + "执行的LogId是[%s]", caseId, executeLogId);
                        log.error(format);
                        throw new ParseException(format);
                    }
                    ApiTestCaseExecuteLogVO caseExecuteLogVO = caseExecuteLogService.findExecute(executeLogId);
                    String responseBody = caseExecuteLogVO.getResponseBody();
                    String responseHeaders = caseExecuteLogVO.getResponseHeaders();
                    log.info("依赖用例responseBody={}", responseBody);
                    log.info("依赖用例responseHeaders={}", responseHeaders);
                    Integer contentType = caseRelyDataTO.getContentType();
                    String expression = relyData.getExtractExpression();
                    try {
                        if(contentType == 0){
                            // json
                            ArrayList jsonPathArray = JSONObject.parseObject(ParseUtil.parseJson(responseBody, expression), ArrayList.class);
                            if (jsonPathArray .isEmpty()) {
                                String nf = String.format("案例依赖项 [%s] json-path 提取的内容为空, " +
                                        "案例编号是 [%s], 执行日志ID为 [%s], 表达式是 [%s]", relyName, caseId, executeLogId, expression);
                                log.error(nf);
                                throw new ParseException(nf);
                            }
                            if (jsonPathArray.size() == 1){
                                Object o = jsonPathArray.get(0);
                                redisUtil.stackPush(chainNo, chainNode(RelyType.INTERFACE_JSON, executeLogId, relyName,
                                        o.toString(), TimeUtil.now() - start, expression));
                                text = text.replace(findStr,o.toString());
                            }else {
                                redisUtil.stackPush(chainNo, chainNode(RelyType.INTERFACE_JSON, executeLogId, relyName,
                                        JSON.toJSONString(jsonPathArray), TimeUtil.now() - start, expression));
                                text = text.replace(findStr,JSON.toJSONString(jsonPathArray));
                            }
                        }else if (contentType ==1){
                            // html
                            ArrayList xpathArray = JSONObject.parseObject(ParseUtil.parseXml(responseBody, expression), ArrayList.class);
                            if (xpathArray.isEmpty()) {
                                String nf = String.format("案例依赖项 [%s] xpath 提取的内容为空, " +
                                        "案例编号是 [%s], 执行日志ID为 [%s], 表达式是 [%s]", relyName, caseId, executeLogId, expression);
                                log.error(nf);
                                throw new ParseException(nf);
                            }
                            if (xpathArray.size() == 1) {
                                Object o = xpathArray.get(0);
                                redisUtil.stackPush(chainNo, chainNode(RelyType.INTERFACE_HTML, executeLogId, relyName, o.toString(), TimeUtil.now() - start, expression));
                                text = text.replace(findStr, o.toString());
                            } else {
                                redisUtil.stackPush(chainNo, chainNode(RelyType.INTERFACE_HTML, executeLogId, relyName, JSON.toJSONString(xpathArray), TimeUtil.now() - start, expression));
                                text = text.replace(findStr, JSON.toJSONString(xpathArray));
                            }
                            log.info("xml提取值并替换后的结果={}", text);
                        }else  if (contentType ==2){
                            // headers
                            ArrayList headerArray = JSONObject.parseObject(ParseUtil.parseJson(responseHeaders, expression), ArrayList.class);
                            if (headerArray == null || headerArray.isEmpty()) {
                                String nf = String.format("案例依赖项 [%s] header's json-path 提取的内容为空,, " +
                                        "案例编号是s [%s],执行日志ID为 [%s], 表达式是 [%s]", relyName, caseId, executeLogId, expression);
                                log.error(nf);
                                throw new ParseException(nf);
                            } else {
                                if (headerArray.size() == 1) {
                                    Object o = headerArray.get(0);
                                    redisUtil.stackPush(chainNo, chainNode(RelyType.INTERFACE_HEADER, executeLogId, relyName, o.toString(), TimeUtil.now() - start, expression));
                                    text = text.replace(findStr, o.toString());
                                } else {
                                    redisUtil.stackPush(chainNo, chainNode(RelyType.INTERFACE_HEADER, executeLogId, relyName, JSON.toJSONString(headerArray), TimeUtil.now() - start, expression));
                                    text = text.replace(findStr, JSON.toJSONString(headerArray));
                                }
                            }
                        }else {
                            throw new ParseException("不支持提取类型");
                        }

                    }
                    catch (ParseException e){
                        String nf = "不支持提取类型。";
                        log.error(nf);
                        throw new ParseException(nf);
                    }

                    catch (Exception e){
                        String nf = String.format("解析依赖错误，错误日志是 [%s]",ExceptionUtil.msg(e));
                        log.error(nf);
                        throw new ParseException(nf);
                    }


                }
            }
        }
        return text;
    }

    /**
     * 提取解析数据
     * @param text 字符串文本数据待解析的
     * @param suiteLogDetailNo 非空使用测试套件，否则使用临时套件
     * @param casePreNo 组合使用前置用例缓存 redis hash key
     * @param chainNo 链路跟踪 redis key
     * @return 解析后的异常
     */
    public String parseProcessor(String text,String suiteLogDetailNo,String casePreNo,String chainNo){
        log.info("-------------------------------------开始处理器提取解析流程------------------------------");
        log.info("-------------------------------------待解析的字符串原文:={}",text);
        // 1. 数据为空直接返回，不处理
        if (text ==null && !text.isEmpty()){
            return text;
        }
        // 2. 正则匹配，匹配到则替换
        Pattern compile = Pattern.compile(ParserConstant.DEPENDENCY_REGEX);
        // 3. 匹配到则替换
        Matcher matcher = compile.matcher(text);
        // 4. 循环匹配
        while (matcher.find()){
            // 获取当前时间,封装的工具类
            long start = TimeUtil.now();
            // 获取匹配到的字符串
            String finds = matcher.group();
            // 从匹配到的字符串中提取处理器名称，假设处理器名称被括号包围，去除括号
            String processorName = finds.substring(2, finds.length() - 1);
            // 根据处理器名称在查询缓存参数
            ApiTestCacheParameterVo cacheParameterByName = cacheParameterService.findCacheParameterByName(processorName);
            // 记录日志，显示待解析的处理器名称
            log.info("--------------------------------------待解析处理器名称={}", processorName);
            Object redisResult;
            // 记录日志，显示当前的前置用例编号
            log.info("--------------------------------------casePreNo={}", casePreNo);
            if (casePreNo == null){
                if (suiteLogDetailNo ==null){
                    // 如果前置用例编号和测试套件详情编号都为空，则使用临时变量域
                    log.info("suiteLogDetailNo == null && casePreNo == null，使用临时变量域");
                    log.info("--------------------------------------测试套件未找到处理器{},使用临时变量域", processorName);
                    redisResult = redisTemplate.opsForHash().get(NoUtil.TEMP_POST_PROCESSOR_NO, processorName);
                }else {
                    // 如果前置用例编号为空但测试套件详情编号不为空，则使用测试套件域
                    log.info("suiteLogDetailNo != null && casePreNo == null，使用测试套件域");
                    log.info("--------------------------------------使用测试套件{}使用处理器{}", suiteLogDetailNo, processorName);
                    redisResult = redisTemplate.opsForHash().get(suiteLogDetailNo, processorName);
                }

            }else {
                // 如果前置用例编号不为空，则使用前置用例域
                log.info("casePreNo != null，使用前置用例域");
                log.info("--------------------------------------使用前置用例{}使用处理器{}", casePreNo, processorName);
                redisResult = redisTemplate.opsForHash().get(casePreNo, processorName);
                // 如果在前置用例域中没有找到缓存结果，则尝试使用临时变量域
                if (redisResult ==null){
                    redisResult = redisTemplate.opsForHash().get(casePreNo, processorName);
                }
            }
            // 如果Redis 中没有找到缓存结果,则记录错误日志并抛出去异常
            if (redisResult == null){
                log.error("--------------------------------------Redis 中没有找到缓存结果,请检查处理器{}是否正确配置", processorName);
                throw new LeaseException(ResultCodeEnum.WEB_API_PROCESSOR_NOT_FOUND);
            }
            // 将缓存结果转成字符串
            String redisResultString = redisResult.toString();
            // 记录日志，显示处理器解析结果
            log.info("--------------------------------------处理器解析结果={}", redisResultString);
            // 将解析后的结果替换到原字符串中，并记录相关信息
            redisUtil.stackPush(chainNo, chainNode(RelyType.READ_PROCESSOR,null,processorName,redisResultString,TimeUtil.now()-start,null));
            // 将原文本中的匹配项替换为解析结果
            text = text.replace(finds, redisResultString);
            // 创建日志对象，记录处理器解析的详细信息
            ApiTestCacheParameterLog cacheParameterLog = new ApiTestCacheParameterLog();
            // 设置对象的名称，如果缓存参数存在则使用缓存参数的名称，否则使用处理器名称
            if (cacheParameterByName != null){
                cacheParameterLog.setName(cacheParameterByName.getName());
            }else {
                cacheParameterLog.setName(processorName);
            }
            // 设置日志对象的值为解析结果
            cacheParameterLog.setValue(redisResultString);
            // 设置日志对象的状态写入次数
            cacheParameterLog.setStatus(0);
            cacheParameterLog.setWr(0);
            // 保存日志信息到数据库
            cacheParameterLogService.saveInterfaceProcessorLog(cacheParameterLog);

        }
        return text;
    }

    /**
     * 提取依赖名称
     * @param text 字符串文本数据待解析的
     * @return 依赖名称的列表
     */
    public ArrayList<String> extractDependencyName(String text) {
        // 创建依赖名称的列表
        ArrayList<String> list = new ArrayList<>();
        if (text == null || text.isEmpty()){
            return list;
        }
        // 开始正则匹配
        String replaceAll = text.replaceAll(ParserConstant.PROCESSOR_REGEX, "");
        Matcher matcher = Pattern.compile(ParserConstant.DEPENDENCY_REGEX).matcher(replaceAll);
        while (matcher.find()) {
            // 获取匹配到的字符串
            String finds = matcher.group();
            // 添加到依赖名称列表
            String dependencyExpression = finds.substring(2, finds.length() - 1);
            if (Pattern.matches(ParserConstant.DEPENDENCY_REGEX_INDEX, dependencyExpression)) { // 数组下班 带有索引 []
                // 匹配到索引
                list.add(dependencyExpression.substring(0,dependencyExpression.indexOf("[")));
            } else if(Pattern.matches(ParserConstant.DEPENDENCY_REGEX_PARAMS, dependencyExpression)) { // 方法或者sql带()
                list.add(dependencyExpression.substring(0,dependencyExpression.indexOf("(")));
            }
            else{ // 普通模式
                // 不匹配到索引，直接添加到列表)
                list.add(dependencyExpression);
            }


        }
        return list;

    }
}
